
#include "Hook.h"

#include <QDebug>

Hook::Hook()
{

}

Hook::~Hook()
{

}

void Hook::HookJmp(void *oldFuncAddr, void *newFuncAddr)
{
    const HookInfo &exsitInfo = m_mapOfFuncAddrToHookInfo[oldFuncAddr];
    if (exsitInfo.NewFuncAddr == newFuncAddr) {
        // 已有跳转数据，则直接更改
        WriteProcessMemory(INVALID_HANDLE_VALUE, oldFuncAddr, (void*)(exsitInfo.NewCode), 5, NULL);
        return;
    }

    HookInfo info;
    info.OldFuncAddr = oldFuncAddr;
    info.NewFuncAddr = newFuncAddr;

    // 读取MessageBoxA函数的前7个字节，并保存在OldCode数组中
    if(ReadProcessMemory(INVALID_HANDLE_VALUE, oldFuncAddr, info.OldCode, 5, NULL) == 0)
    {
        printf("ReadProcessMemory error\n");
        return;
    }

    //printf("OldCode is %x%x%x%x%x%x%x\n", OldCode[0], OldCode[1], OldCode[2], OldCode[3], OldCode[4], OldCode[5], OldCode[6]);

    DWORD JmpAddress = (DWORD)newFuncAddr - (DWORD)oldFuncAddr - 5;  // 获取自定义的MessageBoxA函数的地址

    memcpy(&info.NewCode[1], &JmpAddress, 4);  // 将地址写入到NewCode的第二个字节开始的位置

    DWORD dwOldProtect = 0;  // 用于保存原始页保护
    //printf("NewBytes is %x%x%x%x%x\n", NewCode[0], NewCode[1], NewCode[2], NewCode[3], NewCode[4], NewCode[5], NewCode[6]);

    // 使用VirtualProtect函数改变MessageBoxA函数所在页的保护属性，使其可读可写可执行。
    VirtualProtect(oldFuncAddr, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);

    // 使用WriteProcessMemory函数将我们的Hook代码写入到MessageBoxA函数的开头。
    WriteProcessMemory(INVALID_HANDLE_VALUE, oldFuncAddr, info.NewCode, 5, NULL);

    // 使用VirtualProtect函数恢复MessageBoxA函数所在页的保护属性。
    //VirtualProtect(oldFuncAddr, 5, dwOldProtect, &dwOldProtect);

    m_mapOfFuncAddrToHookInfo.insert(oldFuncAddr, info);
}

void Hook::CloseHookJmp(void *oldFuncAddr)
{
    if(!m_mapOfFuncAddrToHookInfo.contains(oldFuncAddr)) {
        MessageBoxA(NULL, "Hook::CloseHookJmp func have not hooked", "Title", MB_OK);
        return;
    }
    // 恢复原始代码
    const HookInfo &info = m_mapOfFuncAddrToHookInfo.value(oldFuncAddr);
    WriteProcessMemory(INVALID_HANDLE_VALUE, oldFuncAddr, (void*)info.OldCode, 5, NULL);
}

void Hook::LibFuncHookJmp(const QString &libName, const QString &funcName, void *newFuncAddr)
{
    HMODULE hModule = LoadLibraryA(libName.toStdString().data());
    FARPROC oldFuncAddr = GetProcAddress(hModule, funcName.toStdString().data());

    HookJmp((void *)oldFuncAddr, newFuncAddr);
}

void Hook::CloseLibFuncHookJmp(const QString &libName, const QString &funcName)
{
    HMODULE hModule = LoadLibraryA(libName.toStdString().data());
    FARPROC oldFuncAddr = GetProcAddress(hModule, funcName.toStdString().data());

    CloseHookJmp((void *)oldFuncAddr);
}
